package cn.fintecher.pangolin.service.repair.service;

import cn.fintecher.pangolin.common.enums.ApplyFileContent;
import cn.fintecher.pangolin.common.enums.TaskBoxStatus;
import cn.fintecher.pangolin.common.enums.TaskBoxType;
import cn.fintecher.pangolin.common.exception.BadRequestException;
import cn.fintecher.pangolin.common.model.UploadFile;
import cn.fintecher.pangolin.common.model.*;
import cn.fintecher.pangolin.common.utils.*;
import cn.fintecher.pangolin.entity.elastic.*;
import cn.fintecher.pangolin.service.repair.client.WebSocketClient;
import cn.fintecher.pangolin.service.repair.model.request.DataRepairImportRequest;
import cn.fintecher.pangolin.service.repair.respository.*;
import cn.fintecher.pangolin.service.repair.utils.ImportExcelUntil;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.io.FileUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryAction;
import org.elasticsearch.index.reindex.DeleteByQueryRequestBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StopWatch;
import org.springframework.web.client.RestTemplate;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @Author:hanwannan
 * @Desc:
 * @Date:Create in 9:48 2018/9/1
 */
@Service("dataRepairImportService")
public class DataRepairImportService {
    Logger logger = LoggerFactory.getLogger(DataRepairImportService.class);

    //户籍资料导入字段匹配模板
    private static String kosikiDataTemplateMap =
            "{\"姓名\":\"name\","
                    + "\"身份证号\":\"idNo\","
                    + "\"银行\":\"bank\","
                    + "\"申调地区\":\"applyTransferArea\","
                    + "\"户籍\":\"koseki\","
                    + "\"户籍地区\":\"kosekiArea\","
                    + "\"申调时间\":\"applyTransferTime\","
                    + "\"备注\":\"remark\","
                    + "\"服务处所\":\"serviceSpace\","
                    + "\"联系方式\":\"contact\","
                    + "\"新地址\":\"newAddress\","
                    + "\"曾用名\":\"usedName\"}";
    //户籍备注导入字段匹配模板
    private static String kosikiRemarkTemplateMap =
            "{\"姓名\":\"name\","
                    + "\"身份证号\":\"idNo\","
                    + "\"银行\":\"bank\","
                    + "\"申调地区\":\"applyTransferArea\","
                    + "\"申调时间\":\"applyTransferTime\","
                    + "\"户籍地址\":\"kosekiAddress\","
                    + "\"备注\":\"remark\"}";
    //通讯资料导入字段匹配模板
    private static String communicationDataTemplateMap =
            "{\"姓名\":\"name\","
                    + "\"身份证号\":\"idNo\","
                    + "\"银行\":\"bank\","
                    + "\"申调地区\":\"applyTransferArea\","
                    + "\"座机\":\"landLinePhone\","
                    + "\"手机\":\"mobile\","
                    + "\"地址\":\"address\","
                    + "\"申调时间\":\"applyTransferTime\","
                    + "\"备注/欠款金额\":\"remark\","
                    + "\"电话类型\":\"type\"}";
    //社保资料导入字段匹配模板
    private static String socialSecurityDataTemplateMap =
            "{\"姓名\":\"name\","
                    + "\"身份证号\":\"idNo\","
                    + "\"银行\":\"bank\","
                    + "\"申调地区\":\"applyTransferArea\","
                    + "\"申调时间\":\"applyTransferTime\","
                    + "\"户籍地址\":\"kosekiAddress\","
                    + "\"社保号\":\"socialSecurityNo\","
                    + "\"参保时间\":\"attendSecurityTime\","
                    + "\"参保状态\":\"attendSecurityStatus\","
                    + "\"最近缴纳时间\":\"latelyPayTime\","
                    + "\"最近缴费基数\":\"latelyPayBase\","
                    + "\"工作单位\":\"workUnit\","
                    + "\"公司地址\":\"companyAddress\","
                    + "\"公司电话\":\"companyPhone\","
                    + "\"备注\":\"remark\"}";
    //关联关系导入字段匹配模板
    private static String relationshipTemplateMap =
            "{\"姓名\":\"name\","
                    + "\"身份证号\":\"idNo\","
                    + "\"关系\":\"relation\","
                    + "\"关系人姓名\":\"relationPersonName\","
                    + "\"关系人身份证号\":\"relationPersonIdNo\"}";
    //村委资料导入字段匹配模板
    private static String villageCommitteeDataTemplateMap =
            "{\"省份\":\"province\","
                    + "\"城市\":\"city\","
                    + "\"区/县\":\"area\","
                    + "\"镇/乡\":\"town\","
                    + "\"村/居委会\":\"village\","
                    + "\"地区码\":\"areaCode\","
                    + "\"查询人\":\"queryMan\","
                    + "\"查询日期\":\"queryDate\","
                    + "\"联系人\":\"linkman\","
                    + "\"职务\":\"position\","
                    + "\"办公电话\":\"officePhone\","
                    + "\"手机\":\"mobile\","
                    + "\"家庭电话\":\"homePhone\","
                    + "\"备注\":\"remark\"}";
    //特调资料导入字段匹配模板
    private static String specialTransferDataTemplateMap =
            "{\"姓名\":\"name\","
                    + "\"身份证号\":\"idNo\","
                    + "\"银行\":\"bank\","
                    + "\"申调地区\":\"applyTransferArea\","
                    + "\"文件名\":\"fileName\","
                    + "\"与本人关系\":\"relationship\","
                    + "\"证件类型\":\"type\","
                    + "\"户籍地区\":\"kosekiArea\","
                    + "\"查询日期\":\"queryDate\","
                    + "\"备注/金额\":\"remark\","
                    + "\"特调地区\":\"specialTransferArea\"}";

    //计生资料导入字段匹配模板
    private static String familyPlanningAreaMap =
            "{\"姓名\":\"name\","
                    + "\"身份证号\":\"idNo\","
                    + "\"银行\":\"bank\","
                    + "\"申调地区\":\"applyTransferArea\","
                    + "\"申调时间\":\"applyTransferTime\","
                    + "\"计生地址\":\"familyPlanningArea\","
                    + "\"备注\":\"remark\"}";

    @Autowired
    private KosekiDataRepository kosekiDataRepository;
    @Autowired
    private KosekiRemarkRepository kosekiRemarkRepository;
    @Autowired
    private RelationshipRepository relationshipRepository;
    @Autowired
    private SocialSecurityDataRepository socialSecurityDataRepository;
    @Autowired
    private CommunicationDataRepository communicationDataRepository;
    @Autowired
    private VillageCommitteeDataRepository villageCommitteeDataRepository;
    @Autowired
    private SpecialTransferDataRepository specialTransferDataRepository;
    @Autowired
    private SpecialTransferPhotoDataRepository specialTransferPhotoDataRepository;
    @Autowired
    private FamilyPlanningDataRepository familyPlanningDataRepository;
    @Autowired
    private AlipayInfoRepository alipayInfoRepository;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    WebSocketClient webSocketClient;
    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 数据修复资料导入
     *
     * @param request
     * @param inputStream
     * @throws Exception
     */
    @Async
    public void importExcelData(DataRepairImportRequest request, InputStream inputStream, List<String> errorList, RepairFileModel repairFileModel) throws Exception {
        logger.info("资料导入开始.......");
        StopWatch watch = new StopWatch();
        watch.start();

        String batchNumber = ZWDateUtil.fomratterDate(new Date(), "yyyyMMddHHmmss").concat("-").concat(RandomUtil.random6());
        if (request.getImportContentType() == ApplyFileContent.HOUSEHOLD_REGISTER_RESOURCE) {
            //导入户籍资料
            StopWatch watch2 = new StopWatch();
            watch2.start();
            logger.info("解析数据文件开始........");
            String template = ImportExcelUntil.getJsonStr(KosekiData.class);
            List<KosekiData> data = ImportExcelUntil.importExcel(KosekiData.class, template, inputStream, errorList);
            watch2.stop();
            logger.info("解析数据文件结束{}", watch2.getTotalTimeMillis());
            if (data != null && data.size() > 0) {
                data.forEach(kosekiData -> {
                    kosekiData.setBatchNumber(batchNumber);
                });
                Set<String> idNos = data.stream().map(KosekiData::getIdNo).collect(Collectors.toSet());
                DeleteByQueryRequestBuilder deleteByQueryRequestBuilder = DeleteByQueryAction.INSTANCE.
                        newRequestBuilder(elasticsearchTemplate.getClient());
                deleteByQueryRequestBuilder.source("koseki_data").filter(termsQuery("idNo.keyword", idNos)).refresh(true).execute().get();
                kosekiDataRepository.saveAll(data);
            }
        } else if (request.getImportContentType() == ApplyFileContent.HOUSEHOLD_REGISTER_REMARK) {
            //导入户籍备注
            StopWatch watch2 = new StopWatch();
            watch2.start();
            logger.info("解析数据文件开始........");
            String template = ImportExcelUntil.getJsonStr(KosekiRemark.class);
            List<KosekiRemark> data = ImportExcelUntil.importExcel(KosekiRemark.class, template, inputStream, errorList);
            watch2.stop();
            logger.info("解析数据文件结束{}", watch2.getTotalTimeMillis());
            if (data != null && data.size() > 0) {
                data.forEach(kosekiData -> {
                    kosekiData.setBatchNumber(batchNumber);
                });
                kosekiRemarkRepository.saveAll(data);
            }
        } else if (request.getImportContentType() == ApplyFileContent.CONTACT_RELATIONSHIP) {
            //导入关联关系
            StopWatch watch2 = new StopWatch();
            watch2.start();
            logger.info("解析数据文件开始........");
            String template = ImportExcelUntil.getJsonStr(Relationship.class);
            List<Relationship> data = ImportExcelUntil.importExcel(Relationship.class, template, inputStream, errorList);
            watch2.stop();
            logger.info("解析数据文件结束{}", watch2.getTotalTimeMillis());
            if (data != null && data.size() > 0) {
                List<Relationship> relationshipList = new ArrayList<>();
                data.forEach(relationData -> {
                    String idNo = relationData.getIdNo();
                    String relationId = relationData.getRelationPersonIdNo();
                    if (idNo != null && relationId != null && !"".equals(relationId.trim())) {
                        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                        queryBuilder.must(matchPhraseQuery("idNo", idNo)).must(matchPhraseQuery("relationPersonIdNo"
                                , relationId));
                        Iterable<Relationship> searchRelationship = relationshipRepository.search(queryBuilder);
                        searchRelationship.forEach(relationShip -> {
                            relationshipList.add(relationShip);
                        });
                    }
                    relationData.setBatchNumber(batchNumber);
                });
                //删除案件证件与关系人证件相同的重复数据
                if (relationshipList != null && relationshipList.size() > 0) {
                    relationshipRepository.deleteAll(relationshipList);
                }
                relationshipRepository.saveAll(data);
            }
        } else if (request.getImportContentType() == ApplyFileContent.SOCIAL_SECURITY) {
            //导入社保资料
            StopWatch watch2 = new StopWatch();
            watch2.start();
            logger.info("解析数据文件开始........");
            String template = ImportExcelUntil.getJsonStr(SocialSecurityData.class);
            List<SocialSecurityData> data = ImportExcelUntil.importExcel(SocialSecurityData.class, template, inputStream, errorList);
            watch2.stop();
            logger.info("解析数据文件结束{}", watch2.getTotalTimeMillis());
            if (data != null && data.size() > 0) {
                data.forEach(kosekiData -> {
                    kosekiData.setBatchNumber(batchNumber);
                    socialSecurityDataRepository.deleteByIdNo(kosekiData.getIdNo());
                });
                saveSocialSecurityData(data, repairFileModel);
            }
        } else if (request.getImportContentType() == ApplyFileContent.PHONE_RESOURCE) {
            //导入电讯资料（移动，电信，联通，三网，联通宽带，支付宝）
            StopWatch watch2 = new StopWatch();
            watch2.start();
            logger.info("解析数据文件开始........");
            String template = ImportExcelUntil.getJsonStr(CommunicationData.class);
            List<CommunicationData> data = ImportExcelUntil.importExcel(CommunicationData.class, template, inputStream, errorList);
            watch2.stop();
            logger.info("解析数据文件结束{}", watch2.getTotalTimeMillis());
            if (data != null && data.size() > 0) {
                List<CommunicationData> communicationDataList = new ArrayList<>();
                data.forEach(communicationData -> {
                    String idNo = communicationData.getIdNo();
                    String type = communicationData.getType();
                    if (idNo != null && type != null && !"".equals(type.trim())) {
                        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                        queryBuilder.must(matchPhraseQuery("idNo", idNo)).must(matchPhraseQuery("type"
                                , type));
                        Iterable<CommunicationData> searchCommunication = communicationDataRepository.search(queryBuilder);
                        searchCommunication.forEach(communication -> {
                            communicationDataList.add(communication);
                        });
                    }
                    communicationData.setBatchNumber(batchNumber);
                });
                //删除案件证件与类型相同的重复数据
                if (communicationDataList != null && communicationDataList.size() > 0) {
                    communicationDataRepository.deleteAll(communicationDataList);
                }
                communicationDataRepository.saveAll(data);
            }
        } else if (request.getImportContentType() == ApplyFileContent.TOWN_RESOURCE) {
            //导入村委资料
            StopWatch watch2 = new StopWatch();
            watch2.start();
            logger.info("解析数据文件开始........");
            String template = ImportExcelUntil.getJsonStr(VillageCommitteeData.class);
            List<VillageCommitteeData> data = ImportExcelUntil.importExcel(VillageCommitteeData.class, template, inputStream, errorList);
            watch2.stop();
            logger.info("解析数据文件结束{}", watch2.getTotalTimeMillis());
            data.forEach(villageCommitteeData -> {
                villageCommitteeData.setBatchNumber(batchNumber);
                villageCommitteeData.setAddress((Objects.nonNull(villageCommitteeData.getProvince()) ? villageCommitteeData.getProvince() : "")
                        .concat(Objects.nonNull(villageCommitteeData.getCity()) ? villageCommitteeData.getCity() : "")
                        .concat(Objects.nonNull(villageCommitteeData.getArea()) ? villageCommitteeData.getArea() : "")
                        .concat(Objects.nonNull(villageCommitteeData.getTown()) ? villageCommitteeData.getTown() : "")
                        .concat(Objects.nonNull(villageCommitteeData.getVillage()) ? villageCommitteeData.getVillage() : ""));
            });
            if (data != null && data.size() > 0) {
                villageCommitteeDataRepository.saveAll(data);
            }

        } else if (request.getImportContentType() == ApplyFileContent.SPECIAL_RESOURCE) {
            //导入有图资料（特调，计生）
            StopWatch watch2 = new StopWatch();
            watch2.start();
            logger.info("解析数据文件开始........");
            String template = ImportExcelUntil.getJsonStr(SpecialTransferData.class);
            List<SpecialTransferData> data = ImportExcelUntil.importExcel(SpecialTransferData.class, template, inputStream, errorList);
            watch2.stop();
            logger.info("解析数据文件结束{}", watch2.getTotalTimeMillis());
            if (data != null && data.size() > 0) {
                data.forEach(specialTransferData -> specialTransferData.setBatchNumber(batchNumber));
                saveSpecialTransferData(data, repairFileModel);
            }
        }
        watch.stop();
        logger.info("资料导入结束，耗时{}", watch.getTotalTimeMillis());
    }

    /**
     * 保存有图附件
     *
     * @param data
     * @throws Exception
     */
    private void saveSpecialTransferData(List<SpecialTransferData> data, RepairFileModel repairFileModel) throws Exception {
        List<SpecialTransferData> saveData= new ArrayList<>();
        if (Objects.nonNull(repairFileModel)) {
            List<UploadFile> uploadFiles = repairFileModel.getRepairFile();
            Map<String, UploadFile> fileMap = uploadFiles.stream().collect(Collectors.toMap(UploadFile::getOriginalName
                    , uploadFile -> uploadFile));

            for(SpecialTransferData specialTransferData:data){
                saveData.add(specialTransferDataRepository.save(specialTransferData));
            }
            saveSpecialTransferPhotoData(saveData, fileMap);
        }else{
            for(SpecialTransferData specialTransferData:data){
                saveData.add(specialTransferDataRepository.save(specialTransferData));
            }
        }
    }

    /**
     * 清洗去重
     *
     * @param specialTransferDataList
     * @return
     */
    private Collection<SpecialTransferData> specialTransferDataClean(List<SpecialTransferData> specialTransferDataList) {
        Map<String, SpecialTransferData> specialTransferDataMap = new HashMap<>();
        for (SpecialTransferData specialTransferData : specialTransferDataList) {
            SpecialTransferData newSpecialTransferData = specialTransferDataMap.get(specialTransferData.getIdNo());
            if (Objects.isNull(newSpecialTransferData) ||
                    !Objects.equals(newSpecialTransferData.getType(), specialTransferData.getType())) {
                newSpecialTransferData = new SpecialTransferData();
                newSpecialTransferData.setName(specialTransferData.getName());
                newSpecialTransferData.setIdNo(specialTransferData.getIdNo());
                newSpecialTransferData.setBank(specialTransferData.getBank());
                newSpecialTransferData.setApplyTransferArea(specialTransferData.getApplyTransferArea());
                newSpecialTransferData.setRemark(specialTransferData.getRemark());
                newSpecialTransferData.setType(specialTransferData.getType());
                newSpecialTransferData.setImportDate(specialTransferData.getImportDate());
                newSpecialTransferData.setOperatorTime(specialTransferData.getOperatorTime());
                newSpecialTransferData.setBatchNumber(specialTransferData.getBatchNumber());
                specialTransferDataMap.put(specialTransferData.getIdNo(), newSpecialTransferData);
            }
        }
        return specialTransferDataMap.values();
    }

    /**
     * 保存特调计生图片数据
     *
     * @param specialTransferDataList
     * @param fileMap
     */
    private void saveSpecialTransferPhotoData(List<SpecialTransferData> specialTransferDataList
            , Map<String, UploadFile> fileMap) throws Exception {
        List<SpecialTransferPhotoData> specialTransferPhotoDataList = new ArrayList<>();
        for (SpecialTransferData specialTransferData : specialTransferDataList) {
            SpecialTransferPhotoData specialTransferPhotoData = new SpecialTransferPhotoData();

            specialTransferPhotoData.setName(specialTransferData.getName());
            specialTransferPhotoData.setIdNo(specialTransferData.getIdNo());
            specialTransferPhotoData.setParentId(specialTransferData.getId());
            specialTransferPhotoData.setType(specialTransferData.getType());
            specialTransferPhotoData.setRelationIdNo(specialTransferData.getRelationIdNo());
            specialTransferPhotoData.setRelation(specialTransferData.getRelation());
            specialTransferPhotoData.setRemark(specialTransferData.getPhoneRemark());
            specialTransferPhotoData.setCertificatesType(specialTransferData.getCertificatesType());
            specialTransferPhotoData.setImportDate(specialTransferData.getImportDate());
            specialTransferPhotoData.setBatchNumber(specialTransferData.getBatchNumber());
            UploadFile file = fileMap.get(specialTransferData.getIdNo().concat("_").concat(specialTransferData.getFileName()));
            if (Objects.nonNull(file)) {
                specialTransferPhotoData.setFileName(file.getOriginalName());
                specialTransferPhotoData.setFileUrl(file.getUrl());
                specialTransferPhotoData.setDocName(specialTransferData.getIdNo());
            } else {
                throw new BadRequestException(null, "importExcelData", "picture.name.not.match");
            }
            specialTransferPhotoDataList.add(specialTransferPhotoData);
        }
        specialTransferPhotoDataRepository.saveAll(specialTransferPhotoDataList);
    }

    /**
     * 保存电讯附件
     *
     * @param data
     * @throws Exception
     */
    private void saveSocialSecurityData(List<SocialSecurityData> data, RepairFileModel repairFileModel) throws Exception {
        if (Objects.nonNull(repairFileModel)) {
            List<UploadFile> uploadFiles = repairFileModel.getRepairFile();
            Map<String, UploadFile> fileMap = uploadFiles.stream().collect(Collectors.toMap(UploadFile::getOriginalName, uploadFile -> uploadFile));
            data.forEach(model -> {
                try {
                    List<Credential> files = new ArrayList<>();
                    if (ZWStringUtils.isNotEmpty(model.getFileName()) && ZWStringUtils.isNotEmpty(model.getIdNo())) {
                        String[] fileNames = model.getFileName().split("_");
                        for (String filename : fileNames) {
                            UploadFile file = fileMap.get(model.getIdNo().concat("_").concat(filename));
                            Credential credential = new Credential();
                            credential.setFileId(file.getId());
                            credential.setFileName(file.getOriginalName());
                            credential.setFileUrl(file.getUrl());
                            files.add(credential);
                        }
                    }
                    model.setCredentialSet(files);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            });
        }
        Set<String> idNos = data.stream().map(SocialSecurityData::getIdNo).collect(Collectors.toSet());
        DeleteByQueryRequestBuilder deleteByQueryRequestBuilder = DeleteByQueryAction.INSTANCE.
                newRequestBuilder(elasticsearchTemplate.getClient());
        deleteByQueryRequestBuilder.source("social_security_data").filter(termsQuery("idNo.keyword", idNos)).refresh(true).execute().get();
        socialSecurityDataRepository.saveAll(data);
    }


    /**
     * 根据idNo 获取特调资料
     *
     * @param idNo
     * @return
     * @throws Exception
     */
    private SpecialTransferData getSpecialTransferDataByIdNo(String idNo) throws Exception {
        MatchQueryBuilder mqb = QueryBuilders.matchQuery("idNo", idNo);
        Iterable<SpecialTransferData> specialTransferDataIterable = specialTransferDataRepository.search(mqb);
        if (specialTransferDataIterable.iterator().hasNext()) {
            return specialTransferDataIterable.iterator().next();
        }
        return null;
    }

    /**
     * 数据修复导入比较
     *
     * @param request
     * @throws Exception
     */
    @Async
    public void importCompare(DataRepairImportRequest request, InputStream inputStream, UserModel operatorModel) {
        TaskBoxModel taskBoxModel = new TaskBoxModel();
        Snowflake snowflake = new Snowflake((int) (Thread.currentThread().getId() % 1024));
        taskBoxModel.setId(String.valueOf(snowflake.next()));
        sendTaskBoxMessage(taskBoxModel, TaskBoxType.EXPORT, TaskBoxStatus.UN_FINISH, null, null, operatorModel, ZWDateUtil.getNowDateTime(), null, "修复导入比较导出");
        try {
            List<String> errorList = new ArrayList<>();
            //已存在数据
            List<ApplyMaterialModel> hasData = new ArrayList<>();
            //不存在数据
            List<ApplyMaterialModel> repairData = new ArrayList<>();
            StopWatch watch = new StopWatch();
            watch.start();
            logger.info("解析数据文件开始........");
//            String fields = ImportExcelUntil.getFields(ApplyMaterialModel.class);
            List<Map<String, String>> sheetDataList = ImportExcelUntil.parseExcelAssistManagementData(inputStream);
            List<Class<?>> objClassList = new ArrayList<>();
            objClassList.add(ApplyMaterialModel.class);
            Map<String, ImportExcelConfigItem> headMap = ImportExcelUntil.excelConfigItemToMap(sheetDataList, objClassList);
            sheetDataList.remove(0);
            List<ApplyMaterialModel> applyData = new ArrayList<>();
            Long rowIndex = 1L;
            for (Map<String, String> map : sheetDataList) {
                ApplyMaterialModel applyMaterialModel = new ApplyMaterialModel();
                for (Map.Entry<String, String> cellUnit : map.entrySet()) {
                    String cellValue = cellUnit.getValue();
                    ImportExcelConfigItem importExcelConfigItem = headMap.get(cellUnit.getKey());
                    ImportExcelUntil.parseCellMap(applyMaterialModel, cellValue, importExcelConfigItem, errorList, rowIndex, 1);
                }
                applyData.add(applyMaterialModel);
                rowIndex++;
            }
//            List<ApplyMaterialModel> applyData = ImportExcelUntil.importExcel(ApplyMaterialModel.class, fields, inputStream, errorList);
            watch.stop();
            logger.info("解析数据文件结束{}", watch.getTotalTimeMillis());
            if (Objects.equals(request.getImportContentType(), ApplyFileContent.HOUSEHOLD_REGISTER_RESOURCE)) {
                compareHouseInfo(applyData, hasData, repairData);
            } else if (Objects.equals(request.getImportContentType(), ApplyFileContent.HOUSEHOLD_REGISTER_REMARK)) {
                compareHouseRemark(applyData, hasData, repairData);
            } else if (Objects.equals(request.getImportContentType(), ApplyFileContent.CONTACT_RELATIONSHIP)) {
                compareContactRelation(applyData, hasData, repairData);
            } else if (Objects.equals(request.getImportContentType(), ApplyFileContent.SOCIAL_SECURITY)) {
                compareSocialSecurity(applyData, hasData, repairData);
            } else if (Objects.equals(request.getImportContentType(), ApplyFileContent.TOWN_RESOURCE)) {
                compareTownResource(applyData, hasData, repairData);
            } else if (Objects.equals(request.getImportContentType(), ApplyFileContent.PHONE_RESOURCE)) {
                comparePhoneResource(applyData, hasData, repairData);
            } else if (Objects.equals(request.getImportContentType(), ApplyFileContent.SPECIAL_RESOURCE)) {
                compareSpecialResource(applyData, hasData, repairData);
            }

            String filePath = FileUtils.getTempDirectoryPath();
            filePath = filePath.concat("导入比较结果_").concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx");
            List<String> list = new ArrayList<>();
            List<String> properties = new ArrayList<>();
            List<CaseInfoPropertyResponse> responses = ImportExcelUntil.getObjejctPro(objClassList);
            responses.forEach(response -> {
                list.add(response.getName());
                properties.add(response.getAttribute());
            });
            String[] title = new String[list.size()];
            list.toArray(title);
            String[] property = new String[list.size()];
            properties.toArray(property);
            ImportExcelUntil.exportToExcel(hasData, repairData, title, property, filePath, "不存在的数据");
            UploadFile uploadFile = getFileUrl(filePath);
            sendTaskBoxMessage(taskBoxModel, TaskBoxType.EXPORT, TaskBoxStatus.FINISHED, uploadFile.getId(), uploadFile.getOriginalName(), operatorModel, null, ZWDateUtil.getNowDateTime(), "修复导入比较导出");
        } catch (Exception e) {
            e.printStackTrace();
            sendTaskBoxMessage(taskBoxModel, TaskBoxType.EXPORT, TaskBoxStatus.FAILURE, null, null, operatorModel, null, ZWDateUtil.getNowDateTime(), "修复导入比较导出");
        }
    }

    /***
     * 任务盒子
     * @param taskBoxType 盒子类型
     * @param taskBoxStatus 消息状态
     * @param operatorModel 登录用户model
     * @param startTime 开始时间
     * @param endTime 结束时间
     */
    public TaskBoxModel sendTaskBoxMessage(TaskBoxModel taskBoxModel, TaskBoxType taskBoxType, TaskBoxStatus taskBoxStatus,
                                           String fileId, String fileName, UserModel operatorModel, Date startTime, Date endTime, String taskDescribe) {

        taskBoxModel.setTaskBoxType(taskBoxType);
        taskBoxModel.setTaskBoxStatus(taskBoxStatus);
        taskBoxModel.setFileId(fileId);
        taskBoxModel.setFileName(fileName);
        taskBoxModel.setOperator(operatorModel.getId());
        taskBoxModel.setOperatorTime(ZWDateUtil.getNowDateTime());
        if (Objects.nonNull(taskDescribe)) {
            taskBoxModel.setTaskDescribe(taskDescribe);
        }
        if (Objects.nonNull(startTime)) {
            taskBoxModel.setBeginDate(startTime);
        }
        if (Objects.nonNull(endTime)) {
            taskBoxModel.setEndDate(endTime);
        }
        webSocketClient.sendTaskByUserId(taskBoxModel, operatorModel.getUsername());
        return taskBoxModel;
    }

    public UploadFile getFileUrl(String filePath) {
        FileSystemResource resource = new FileSystemResource(filePath);
        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        param.add("file", resource);
        ResponseEntity<UploadFile> response = restTemplate.postForEntity(InnerServiceUrl.COMMON_SERVICE_UPLOADFILE, param, UploadFile.class);
        return response.getBody();
    }

    private void compareHouseInfo(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasData, List<ApplyMaterialModel> repairData) {
        List<String> idCards = applyData.stream().map(ApplyMaterialModel::getCertificateNo).collect(Collectors.toList());
        List<KosekiData> kosekiDatas = IterableUtils.toList(kosekiDataRepository.search(QueryBuilders.boolQuery().must(termsQuery("idNo.keyword", idCards))));
        List<String> hasIdCards = kosekiDatas.stream().map(KosekiData::getIdNo).collect(Collectors.toList());
        for (ApplyMaterialModel model : applyData) {
            if (hasIdCards.contains(model.getCertificateNo())) {
                hasData.add(model);
            } else {
                repairData.add(model);
            }
        }
    }

    private void compareHouseRemark(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasDate, List<ApplyMaterialModel> repairDate) {
        List<String> idCards = applyData.stream().map(ApplyMaterialModel::getCertificateNo).collect(Collectors.toList());
        List<KosekiRemark> kosekiRemarks = IterableUtils.toList(kosekiRemarkRepository.search(QueryBuilders.boolQuery().must(termsQuery("idNo.keyword", idCards))));
        List<String> hasIdCards = kosekiRemarks.stream().map(KosekiRemark::getIdNo).collect(Collectors.toList());
        for (ApplyMaterialModel model : applyData) {
            if (hasIdCards.contains(model.getCertificateNo())) {
                hasDate.add(model);
            } else {
                repairDate.add(model);
            }
        }
    }

    private void compareContactRelation(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasDate, List<ApplyMaterialModel> repairDate) {
        List<String> idCards = applyData.stream().map(ApplyMaterialModel::getCertificateNo).collect(Collectors.toList());
        List<Relationship> relationships = IterableUtils.toList(relationshipRepository.search(QueryBuilders.boolQuery().must(termsQuery("idNo.keyword", idCards))));
        List<String> hasIdCards = relationships.stream().map(Relationship::getIdNo).collect(Collectors.toList());
        for (ApplyMaterialModel model : applyData) {
            if (hasIdCards.contains(model.getCertificateNo())) {
                hasDate.add(model);
            } else {
                repairDate.add(model);
            }
        }
    }

    private void compareSocialSecurity(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasDate, List<ApplyMaterialModel> repairDate) {
        List<String> idCards = applyData.stream().map(ApplyMaterialModel::getCertificateNo).collect(Collectors.toList());
        List<SocialSecurityData> socialSecurityDatas = IterableUtils.toList(socialSecurityDataRepository.search(QueryBuilders.boolQuery().must(termsQuery("idNo.keyword", idCards))));
        List<String> hasIdCards = socialSecurityDatas.stream().map(SocialSecurityData::getIdNo).collect(Collectors.toList());
        for (ApplyMaterialModel model : applyData) {
            if (hasIdCards.contains(model.getCertificateNo())) {
                hasDate.add(model);
            } else {
                repairDate.add(model);
            }
        }
    }

    private void compareTownResource(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasDate, List<ApplyMaterialModel> repairDate) {

    }

    private void comparePhoneResource(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasDate, List<ApplyMaterialModel> repairDate) {
        List<String> idCards = applyData.stream().map(ApplyMaterialModel::getCertificateNo).collect(Collectors.toList());
        List<CommunicationData> communicationDatas = IterableUtils.toList(communicationDataRepository.search(QueryBuilders.boolQuery().must(termsQuery("idNo.keyword", idCards))));
        List<String> hasIdCards = communicationDatas.stream().map(CommunicationData::getIdNo).collect(Collectors.toList());
        for (ApplyMaterialModel model : applyData) {
            if (hasIdCards.contains(model.getCertificateNo())) {
                hasDate.add(model);
            } else {
                repairDate.add(model);
            }
        }
    }

    private void comparePlannedResource(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasDate, List<ApplyMaterialModel> repairDate) {
        List<String> idCards = applyData.stream().map(ApplyMaterialModel::getCertificateNo).collect(Collectors.toList());
        List<FamilyPlanningData> familyPlanningDatas = IterableUtils.toList(familyPlanningDataRepository.search(QueryBuilders.boolQuery().must(termsQuery("idNo", idCards))));
        List<String> hasIdCards = familyPlanningDatas.stream().map(FamilyPlanningData::getIdNo).collect(Collectors.toList());
        for (ApplyMaterialModel model : applyData) {
            if (hasIdCards.contains(model.getCertificateNo())) {
                hasDate.add(model);
            } else {
                repairDate.add(model);
            }
        }
    }

    private void comparePayInfo(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasDate, List<ApplyMaterialModel> repairDate) {
        List<String> idCards = applyData.stream().map(ApplyMaterialModel::getCertificateNo).collect(Collectors.toList());
        List<AlipayInfo> alipayInfos = IterableUtils.toList(alipayInfoRepository.search(QueryBuilders.boolQuery().must(termsQuery("idNo", idCards))));
        List<String> hasIdCards = alipayInfos.stream().map(AlipayInfo::getIdNo).collect(Collectors.toList());
        for (ApplyMaterialModel model : applyData) {
            if (hasIdCards.contains(model.getCertificateNo())) {
                hasDate.add(model);
            } else {
                repairDate.add(model);
            }
        }
    }

    private void compareSpecialResource(List<ApplyMaterialModel> applyData, List<ApplyMaterialModel> hasDate, List<ApplyMaterialModel> repairDate) {
        List<String> idCards = applyData.stream().map(ApplyMaterialModel::getCertificateNo).collect(Collectors.toList());
        List<SpecialTransferData> specialTransferDatas = IterableUtils.toList(specialTransferDataRepository.search(QueryBuilders.boolQuery().must(termsQuery("idNo.keyword", idCards))));
        List<String> hasIdCards = specialTransferDatas.stream().map(SpecialTransferData::getIdNo).collect(Collectors.toList());
        for (ApplyMaterialModel model : applyData) {
            if (hasIdCards.contains(model.getCertificateNo())) {
                hasDate.add(model);
            } else {
                repairDate.add(model);
            }
        }
    }

}
